﻿using ArcEngine.CourseDesign.Win.Util;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.DisplayUI;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ArcEngine.CourseDesign.Win
{
    public partial class FrmMain : UIForm
    {
        public FrmMain()
        {
            InitializeComponent();
            this.MapInit();
        }

        private void navMenu_MenuItemClick(string itemText, int menuIndex, int pageIndex)
        {
            if ("高亮显示三角形内部的风力发电机".Equals(itemText))
            {
                this.HightLightOnTrianglePolygon();
            }
            else if ("导出2010年建的风力发电机".Equals(itemText))
            {
                this.ImportShp_fl2010();
            }
            else if ("高亮显示寿光区的风力发电机".Equals(itemText))
            {
                this.HightLightInShouguangCity();
            }
            else if ("选择出高程值大于500的风力发电机".Equals(itemText))
            {
                this.SelectElevation_MoreThan500();
            }
            else if ("显示三维地形".Equals(itemText))
            {
                this.DispalyAs3D();
            }
            else if ("裁剪高密市高程数据".Equals(itemText))
            {
                this.RasterClip_GaoMICity();
            }
            else if ("给风力发电机属性表添加X、Y字段及数据".Equals(itemText))
            {
                this.AddFields();
            }
            else
            {
                base.ShowErrorDialog("没有这个功能(¬_¬ )");
            }
        }


        // todo 1、项目初始化时，加载风力发电机、潍坊区划数据、数字高程模型
        private void MapInit()
        {
            try
            {
                string baseDir = AppDomain.CurrentDomain.BaseDirectory;
                string fl_shp_fullPath = System.IO.Path.Combine(baseDir, "data\\风力发电机.shp");
                string wf_shp_fullPath = System.IO.Path.Combine(baseDir, "data\\潍坊区划.shp");
                string wf_raster_fullPath = System.IO.Path.Combine(baseDir, "data\\潍坊高程.tif");
                IFeatureLayer fl_shp = MapHelper.LoadShp(fl_shp_fullPath);
                IFeatureLayer wf_shp = MapHelper.LoadShp(wf_shp_fullPath);
                IRasterLayer wf_raster = MapHelper.LoadRaster(wf_raster_fullPath);
                this.axMapControl.Map.AddLayer(wf_raster);
                this.axMapControl.Map.AddLayer(wf_shp);
                this.axMapControl.Map.AddLayer(fl_shp);
                this.axMapControl.ActiveView.Refresh();
            }
            catch (Exception ex)
            {
                base.ShowErrorDialog(ex.Message);
                return;
            }
        }

        // todo 2、具备导航工具条，包括放大、缩小、平移、全图、刷新视图。你看，就在界面上

        // todo 3、在地图上任选三个点，画出这三个点构成的三角形，并高亮显示三角形内部的风力发电机
        private void HightLightOnTrianglePolygon()
        {
            IPointCollection selectedPoints = new MultipointClass();
            // 添加点
            ISelection selected = this.axMapControl.Map.FeatureSelection;
            IEnumFeatureSetup enumFeatureSetup = selected as IEnumFeatureSetup;
            enumFeatureSetup.AllFields = true;
            IEnumFeature enumFeature = enumFeatureSetup as IEnumFeature;
            enumFeature.Reset();
            IFeature feature = enumFeature.Next();
            while (null != feature)
            {
                if (feature.Shape is IPoint point)
                {
                    object a = Type.Missing;
                    selectedPoints.AddPoint(point, ref a, ref a);
                }
                feature = enumFeature.Next();
            }
            // 生成面
            if (selectedPoints.PointCount == 3)
            {
                Ring ring = new RingClass();
                object missing = Type.Missing;
                ring.AddPointCollection(selectedPoints);
                IGeometryCollection pointsPolygon = new PolygonClass();
                pointsPolygon.AddGeometry(ring as IGeometry, ref missing, ref missing);
                IPolygon polygon = pointsPolygon as IPolygon;
                polygon.SimplifyPreserveFromTo();
                IElement polygonElement = new PolygonElementClass()
                {
                    Geometry = polygon
                };
                IGraphicsContainer graphicsContainer = this.axMapControl.Map as IGraphicsContainer;
                graphicsContainer.AddElement(polygonElement, 0);
                // 高亮显示三角面上的风力发电机
                this.axMapControl.Map.SelectByShape(polygonElement.Geometry, null, false);

                this.axMapControl.Refresh();
            }
            else
            {
                UIMessageTip.ShowError("选择3个点就OK啦");
                return;
            }
        }

        // todo 4、点击风力发电机时，显示风力发电机的建成年份。选择要素后，双击点要素
        private void axMapControl_OnDoubleClick(object sender, IMapControlEvents2_OnDoubleClickEvent e)
        {
            ISelection selected = this.axMapControl.Map.FeatureSelection;
            IEnumFeatureSetup enumFeatureSetup = selected as IEnumFeatureSetup;
            enumFeatureSetup.AllFields = true;
            IEnumFeature enumFeature = enumFeatureSetup as IEnumFeature;
            enumFeature.Reset();
            IFeature feature = enumFeature.Next();
            while (null != feature)
            {
                int index = feature.Fields.FindField("建成年份");
                if (-1 != index)
                {
                    string buildYear = feature.Value[index].ToString();
                    base.ShowInfoTip($"建成年份：{buildYear}年");
                }
                feature = enumFeature.Next();
            }
        }

        // todo 5、单独将2010年建的风力发电机生成一份新数据。导出的文件在这里 ~/bin/Debug/output 有点慢耐心等等
        private void ImportShp_fl2010()
        {
            IFeatureLayer featureLayer = this.axMapControl.GetShpFeatureLayerByName("风力发电机");
            if (null != featureLayer)
            {
                IPointCollection pointCollection = new MultipointClass();
                // 查询建成年份为2010的风力发电站
                IQueryFilter queryFilter = new QueryFilterClass()
                {
                    WhereClause = "建成年份=2010"
                };
                IFeatureCursor featureCursor = featureLayer.Search(queryFilter, false);
                IFeature feature = featureCursor.NextFeature();
                while (null != feature)
                {
                    if (feature.Shape is IPoint point)
                    {
                        object a = Type.Missing;
                        pointCollection.AddPoint(point, ref a, ref a);
                    }
                    feature = featureCursor.NextFeature();
                }

                try
                {
                    // 导出这些矢量点数据
                    IGeoDataset geoDataset = featureLayer as IGeoDataset;
                    ISpatialReference spatialReference = geoDataset.SpatialReference;
                    string filFullPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "output\\风力发电站_2010年.shp");
                    pointCollection.SaveAsShp(filFullPath, spatialReference);
                    UIMessageTip.ShowOk("导出完成");
                }
                catch (Exception ex)
                {
                    base.ShowErrorDialog(ex.Message);
                    return;
                }
            }
            else
            {
                base.ShowInfoTip("图层风力发电机不存在", 2000);
            }
        }

        // todo 6、选择出位于寿光市的风力发电机，高亮显示。
        private void HightLightInShouguangCity()
        {
            // 找到寿光市
            IFeatureLayer wf_FeatureLayer = this.axMapControl.GetShpFeatureLayerByName("潍坊区划");
            if (null != wf_FeatureLayer)
            {
                IFeatureClass featureClass = wf_FeatureLayer.FeatureClass;
                IQueryFilter queryFilter = new QueryFilterClass()
                {
                    WhereClause = "NAME99='寿光市'"
                };
                IFeatureCursor featureCursor = featureClass.Search(queryFilter, false);
                IFeature sg_lineFeature = featureCursor.NextFeature();
                // 查询位于寿光市的点
                ISpatialFilter spatialFilter = new SpatialFilterClass()
                {
                    Geometry = sg_lineFeature.Shape,
                    SpatialRel = esriSpatialRelEnum.esriSpatialRelContains
                };
                IFeatureLayer fl_FeatureLayer = this.axMapControl.GetShpFeatureLayerByName("风力发电机");
                if (null != fl_FeatureLayer)
                {
                    IFeatureCursor pointFeatureCursor = fl_FeatureLayer.Search(spatialFilter, false);
                    // 将查询到的点高亮显示
                    IFeature pointFeature = pointFeatureCursor.NextFeature();
                    while (null != pointFeature)
                    {
                        if (pointFeature.Shape is IPoint)
                        {
                            this.axMapControl.Map.SelectFeature(fl_FeatureLayer, pointFeature);
                        }
                        pointFeature = pointFeatureCursor.NextFeature();
                    }
                    this.axMapControl.Refresh();
                }
                else
                {
                    base.ShowInfoTip("图层风力发电机不存在", 2000);
                }
            }
            else
            {
                base.ShowInfoTip("图层潍坊区划不存在", 2000);
            }
        }

        // todo 7、选择出高程值大于500的风力发电机。不会 ╮(╯▽╰)╭
        private void SelectElevation_MoreThan500()
        {
            base.ShowWarningDialog("不会(╬▔皿▔)");
        }

        // todo 8、将风力发电机显示在三维地形上，二维显示与三维显示在同一个项目中。
        private void DispalyAs3D()
        {
            this.tabControl_Toc.SelectedTab = this.tabControl_Toc.TabPages[1];
            this.axSceneControl.LoadSxFile(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data\\三维显示.sxd"));
            this.axSceneControl.Refresh();
        }

        // todo 9、裁剪出高密市的数字高程模型数据。裁剪的文件在这里 ~/bin/Debug/output 有点慢耐心等等
        private void RasterClip_GaoMICity()
        {
            // 找到高密市
            IFeatureLayer gm_FeatureLayer = this.axMapControl.GetShpFeatureLayerByName("潍坊区划");
            if (null != gm_FeatureLayer)
            {
                IFeatureClass featureClass = gm_FeatureLayer.FeatureClass;
                IQueryFilter queryFilter = new QueryFilterClass()
                {
                    WhereClause = "NAME99='高密市'"
                };
                IFeatureCursor featureCursor = featureClass.Search(queryFilter, false);
                IFeature gm_lineFeature = featureCursor.NextFeature();
                // 裁剪
                IRasterLayer rasterLayer = this.axMapControl.GetRatserFeatureLayerByName("潍坊高程.tif");
                if (null != rasterLayer)
                {
                    try
                    {
                        RasterOperate.Clip(rasterLayer, gm_lineFeature, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "output\\高密市.tif"));
                        UIMessageTip.ShowOk("裁剪完成");
                    }
                    catch (Exception ex)
                    {
                        base.ShowErrorDialog(ex.Message);
                        return;
                    }
                }
                else
                {
                    base.ShowInfoTip("图层潍坊高程.tif不存在", 2000);
                }
            }
            else
            {
                base.ShowInfoTip("图层潍坊区划不存在", 2000);
            }
        }

        // todo 10、在风力发电机数据属性表中添加两个字段：X坐标、Y坐标，并添加坐标值。这个是有问题的，运行不会成功
        private void AddFields()
        {
            IFeatureLayer fl_FeatureLayer = this.axMapControl.GetShpFeatureLayerByName("风力发电机");
            IFeatureClass featureClass = fl_FeatureLayer.FeatureClass;
            // 添加X、Y字段
            IClass cls = featureClass;
            if (cls.FindField("X") == -1)
            {
                IField x_field = this.AddField("X", fl_FeatureLayer);
                cls.AddField(x_field);
            }
            if (cls.FindField("Y") == -1)
            {
                IField y_field = this.AddField("Y", fl_FeatureLayer);
                cls.AddField(y_field);
            }
            // 开启编辑状态
            IDataset dataset = (IDataset)featureClass;
            IWorkspace workspace = dataset.Workspace;
            IWorkspaceEdit workspaceEdit = (IWorkspaceEdit)workspace;
            workspaceEdit.StartEditing(true);
            workspaceEdit.StartEditOperation();
            // 循环所有的风力发电机
            IFeatureCursor featureCursor = fl_FeatureLayer.Search(null, false);
            IFeature feature = featureCursor.NextFeature();
            while (null != feature)
            {
                if (feature.Shape is IPoint point)
                {
                    try
                    {
                        int x_index = feature.Fields.FindField("X");
                        int y_index = feature.Fields.FindField("Y");
                        point.QueryCoords(out double x, out double y);
                        if (!double.IsNaN(x) && !double.IsNaN(y))
                        {
                            feature.set_Value(x_index, x);
                            feature.set_Value(y_index, y);
                        }
                        else
                        {
                            feature.set_Value(x_index, 0);
                            feature.set_Value(y_index, 0);
                        }
                    }
                    catch (Exception ex)
                    {
                        base.ShowInfoTip(ex.Message);
                        return;
                    }
                }
                feature = featureCursor.NextFeature();
            }
            UIMessageTip.ShowOk("字段赋值完成");
        }

        private IField AddField(string fieldName, IFeatureLayer featureLayer)
        {
            IField field = new FieldClass();
            IFieldEdit fieldEdit = (IFieldEdit)field;
            fieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
            fieldEdit.Name_2 = fieldName;
            //设置坐标系
            IGeometryDef geometryDef = new GeometryDefClass();
            IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef;
            geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;
            IGeoDataset geoDataset = featureLayer as IGeoDataset;
            geometryDefEdit.SpatialReference_2 = geoDataset.SpatialReference; ;
            fieldEdit.GeometryDef_2 = geometryDef;
            return field;
        }

        #region 地图坐标及单位

        private void axMapControl_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
        {
            string mapUnit = this.axMapControl.GetMapUnit();
            this.lbl_MapInfo.Text = $"当前坐标：({e.mapX},{e.mapY})   单位：{mapUnit}";
        }

        #endregion

        #region 记录当前选择图层索引

        private IFeatureLayer _iCurrFeatureLayer = null;
        private ESRI.ArcGIS.Geometry.Point _moveLayerPoint = new ESRI.ArcGIS.Geometry.Point();
        private ILayer _moveLayer = null;
        private int _toIndex = 0;
        private void axTOCControl_2DToc_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)
        {
            try
            {
                if (e.button == 2)
                {
                    esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
                    IBasicMap map = null;
                    ILayer layer = null;
                    object unk = null;
                    object data = null;
                    this.axTOCControl_2DToc.HitTest(e.x, e.y, ref item, ref map, ref layer, ref unk, ref data);
                    this._iCurrFeatureLayer = layer as IFeatureLayer;
                    if (item == esriTOCControlItem.esriTOCControlItemLayer && null != this._iCurrFeatureLayer)
                    {
                        this.contextMenuStrip.Show(MousePosition);
                    }
                }
                if (e.button == 1)
                {
                    esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
                    IBasicMap map = null;
                    object unk = null;
                    object data = null;
                    ILayer layer = null;
                    this.axTOCControl_2DToc.HitTest(e.x, e.y, ref item, ref map, ref layer, ref unk, ref data);
                    if (layer == null) return;

                    this._moveLayerPoint.PutCoords(e.x, e.y);
                    if (item == esriTOCControlItem.esriTOCControlItemLayer)
                    {
                        if (layer is IAnnotationSublayer)
                        {
                            return;
                        }
                        else
                        {
                            this._moveLayer = layer;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                base.ShowErrorDialog(ex.Message);
                return;
            }
        }

        private void axTOCControl_2DToc_OnMouseUp(object sender, ITOCControlEvents_OnMouseUpEvent e)
        {
            try
            {
                if (e.button == 1 && null != this._moveLayer && this._moveLayerPoint.Y != e.y)
                {
                    esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
                    IBasicMap basicMap = null;
                    object unk = null;
                    object data = null;
                    ILayer layer = null;
                    this.axTOCControl_2DToc.HitTest(e.x, e.y, ref item, ref basicMap, ref layer, ref unk, ref data);
                    IMap map = this.axMapControl.ActiveView.FocusMap;
                    if (item == esriTOCControlItem.esriTOCControlItemLayer || null != layer)
                    {
                        if (this._moveLayer != layer)
                        {
                            ILayer tempLayer = null;
                            //获得鼠标弹起时所在图层的索引号
                            for (int i = 0; i < map.LayerCount; i++)
                            {
                                tempLayer = map.get_Layer(i);
                                if (tempLayer == layer)
                                {
                                    this._toIndex = i;
                                }
                            }
                        }
                    }
                    //移动到最前面
                    else if (item == esriTOCControlItem.esriTOCControlItemMap)
                    {
                        this._toIndex = 0;
                    }
                    //移动到最后面
                    else if (item == esriTOCControlItem.esriTOCControlItemNone)
                    {
                        this._toIndex = map.LayerCount - 1;
                    }
                    map.MoveLayer(this._moveLayer, this._toIndex);
                    this.axMapControl.ActiveView.Refresh();
                    this.axTOCControl_2DToc.Update();
                }
            }
            catch (Exception ex)
            {
                base.ShowErrorDialog(ex.Message);
                return;
            }
        }

        #endregion

        #region 打开属性表

        private FrmAttrTable _frmAttrTable = null;
        private void btn_OpenAttrTable_Click(object sender, EventArgs e)
        {
            if (null == this._frmAttrTable || this._frmAttrTable.IsDisposed)
            {
                this._frmAttrTable = new FrmAttrTable();
            }
            this._frmAttrTable.CurrFeatureLayer = this._iCurrFeatureLayer;
            this._frmAttrTable.InitUI();
            this._frmAttrTable.ShowDialog();
        }

        #endregion

        #region 移除图层

        private void btn_RemoveLayer_Click(object sender, EventArgs e)
        {
            if (this._iCurrFeatureLayer == null) return;
            this.axMapControl.Map.DeleteLayer(this._iCurrFeatureLayer);
            this.axMapControl.ActiveView.Refresh();
        }

        #endregion

        #region 选项卡切换

        private void tabControl_Toc_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.tabControl_Toc.SelectedIndex == 0)
            {
                this.tabControl_Map.SelectedTab = this.tabControl_Map.TabPages[0];
            }
            else if (this.tabControl_Toc.SelectedIndex == 1)
            {
                this.tabControl_Map.SelectedTab = this.tabControl_Map.TabPages[1];
            }
        }

        private void tabControl_Map_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.tabControl_Map.SelectedIndex == 0)
            {
                this.tabControl_Toc.SelectedTab = this.tabControl_Toc.TabPages[0];
            }
            else if (this.tabControl_Map.SelectedIndex == 1)
            {
                this.tabControl_Toc.SelectedTab = this.tabControl_Toc.TabPages[1];
            }
        }


        #endregion
    }
}
